﻿/*
	This file is part of Limpet.

    Limpet is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Limpet is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with Limpet.  If not, see http://www.gnu.org/licenses/.
	
	Copyright 2010 Dan Popick
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text;
using System.Web;
using System.Web.Caching;
using System.Web.SessionState;
using System.Web.UI;
using System.Xml;

namespace Open.Web.Diagnostics.Limpet.Modules
{
    /// <summary>
    /// A Limpet module which includes data on the server
    /// </summary>
    public class ServerStateModule: ISelfRenderingLimpetModule
    {
        List<PerformanceCounter> _list = new List<PerformanceCounter>();

        // Constructor preloads the performance counter list
        public ServerStateModule(string name, XmlNode configurationNode)
        {
            Name = name;

            foreach (XmlNode xnode in configurationNode.SelectNodes("counter"))
            {
                XmlAttribute instanceName = xnode.Attributes["instanceName"];
                string cat = GetAttributeValue(xnode, "category");
                string cname = GetAttributeValue(xnode, "name");

                try
                {
                    if (instanceName == null)
                        _list.Add(new PerformanceCounter(cat, cname));
                    else
                        _list.Add(new PerformanceCounter(cat, cname, instanceName.Value));
                }
                catch (Exception ex)
                {
                    Trace.WriteLine(
                        String.Format("Limpet ServerStateModule was unable to find performance counter {0}\\{1}: {2}",
                        cat, cname, ex.ToString()));
                }
            }
        }

        // helper method to get a string attribute value based on a node name, throwing if
        // the attribute is missing
        string GetAttributeValue(XmlNode node, string name)
        {
            XmlAttribute attr = node.Attributes[name];
            if (attr == null)
                throw new ArgumentNullException(
                    String.Format("Attribute '{0}' is required on the counter node", name));

            return attr.Value;
        }

        #region ISelfRenderingLimpetModule Members

        /// <summary>
        /// Renders the details for this module 
        /// </summary>
        /// <param name="stream">
        /// A <see cref="Stream"/> on which to write the contents of the details
        /// </param>
        public void RenderDetails(Stream stream)
        {
            HttpSessionState session = HttpContext.Current.Session;

            TextWriter tw = new StreamWriter(stream);
            HtmlTextWriter writer = new HtmlTextWriter(tw);

            writer.BeginRender();
            writer.RenderBeginTag(HtmlTextWriterTag.H2);
            writer.WriteEncodedText("Server State for " + System.Environment.MachineName);
            writer.RenderEndTag();

            writer.RenderBeginTag(HtmlTextWriterTag.Table);
            writer.RenderBeginTag(HtmlTextWriterTag.Tr);
            writer.RenderBeginTag(HtmlTextWriterTag.Th);
            writer.WriteEncodedText("Category");
            writer.RenderEndTag();
            writer.RenderBeginTag(HtmlTextWriterTag.Th);
            writer.WriteEncodedText("Counter");
            writer.RenderEndTag();
            writer.RenderBeginTag(HtmlTextWriterTag.Th);
            writer.WriteEncodedText("Instance");
            writer.RenderEndTag();
            writer.RenderBeginTag(HtmlTextWriterTag.Th);
            writer.WriteEncodedText("Value");
            writer.RenderEndTag();
            writer.RenderEndTag();

            foreach (PerformanceCounter pc in _list)
            {
                writer.RenderBeginTag(HtmlTextWriterTag.Tr);
                writer.RenderBeginTag(HtmlTextWriterTag.Td);
                writer.WriteEncodedText(pc.CategoryName);
                writer.RenderEndTag();
                writer.RenderBeginTag(HtmlTextWriterTag.Td);
                writer.WriteEncodedText(pc.CounterName);
                writer.RenderEndTag();
                writer.RenderBeginTag(HtmlTextWriterTag.Td);
                writer.WriteEncodedText(pc.InstanceName ?? String.Empty);
                writer.RenderEndTag();
                writer.RenderBeginTag(HtmlTextWriterTag.Td);
                writer.WriteEncodedText(pc.NextValue().ToString("#,##0.00"));
                writer.RenderEndTag();
                writer.RenderEndTag();
            }
            writer.RenderEndTag();

            writer.Flush();
        }

        #endregion

        #region ILimpetModule Members

        /// <summary>
        /// The name, as defined in the config file
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// Gets a single-line HTML message to display in the Limpet popup.
        /// </summary>
        /// <param name="context">The current HTTP context</param>
        /// <returns>A string of HTML to display in the popup.</returns>
        public SummaryMessage GetMessage(System.Web.HttpContext context)
        {
            HttpSessionState session = HttpContext.Current.Session;
            string message;
            if (_list.Count > 0)
            {
                message = String.Format("{0}: {1} {2:##0.0}",
                        System.Environment.MachineName,
                        _list[0].CounterName,
                        _list[0].NextValue());
            }
            else 
            {
                message = System.Environment.MachineName;
            }

            return new SummaryMessage()
                {
                    Category = "Server",
                    Severity = LimpetSeverity.Debug,
                    Text = message,
                    Url = LimpetManager.GetSelfRenderingUrl(Name)
                };
        }

        #endregion
    }
}
